using System.Collections.Generic;
using UnityEngine;

namespace Gj
{
    public class LifePart : BasePart
    {
        public static int statusIndex = 100;
        public static int statusLength = 20;
        private bool _checkStatus;
        private Notice _notice;

        private Life _self;
        public Dictionary<string, SwitchEffect> effectMap = new();

        [HideInInspector] public Status[] statusList = new Status[statusLength];

        public void Init(Life target)
        {
            _self = target;
        }

        public void Set(Notice notice)
        {
            _notice = notice;
        }

        public void Clear()
        {
            for (var i = 0; i < statusList.Length; i++)
            {
                if (!statusList[i].ing) continue;
                OnUpdateStatus(i, 0);
                if (statusList[i].buff.effect != null) RemoveEffect(statusList[i].buff.effect);
            }

            CloseCheck();
        }

        private void OpenCheck()
        {
            if (!_checkStatus)
            {
                InvokeRepeating("CheckStatus", 1, 1);
                _checkStatus = true;
            }
        }

        private void CloseCheck()
        {
            if (_checkStatus)
            {
                CancelInvoke("CheckStatus");
                _checkStatus = false;
            }
        }

        public void UpdateStatus(int index, Status status)
        {
            statusList[index] = status;
            statusList[index].ing = true;

            OpenCheck();
        }

        public void AddBuffs(DataObject cast, int[] buffIds, int time)
        {
            if (buffIds == null) return;
            foreach (var buff in buffIds) AddBuff(cast, buff, time);
        }

        public void AddBuff(DataObject cast, int buffId, int time)
        {
            AddBuff(cast, buffId, 1, time);
        }

        public void AddBuff(DataObject cast, int buffId, int number, int time)
        {
            var first = -1;
            var index = -1;
            if (number <= 0) number = 1;
            for (var i = 0; i < statusList.Length; i++)
            {
                if (!statusList[i].ing) first = i;

                if (statusList[i].ing && statusList[i].buff.refInfo.id == buffId && statusList[i].cast == cast)
                {
                    index = i;
                    break;
                }
            }

            if (index >= 0)
            {
                if (statusList[index].buff.overlying) number += statusList[index].number;
                if (statusList[index].buff.sustainedTime > 0)
                    statusList[index].time += statusList[index].buff.sustainedTime;
            }
            else if (first >= 0)
            {
                index = first;
                var buff = EngineService.single.GetBuff(buffId);
                statusList[index].buff = buff;
                if (buff.sustainedTime > 0)
                    statusList[index].time = time + buff.sustainedTime;
                else
                    statusList[index].time = -1;
                if (buff.intervalTime > 0)
                    statusList[index].lastTime = 0;
                else
                    statusList[index].lastTime = -1;
                statusList[index].cast = cast;

                if (statusList[index].buff.effect != null) AddEffect(statusList[index].buff.effect);
            }
            else
            {
                return;
            }

            OnUpdateStatus(index, number);

            OpenCheck();
        }

        public int FindBuff(Cast cast, int buffId)
        {
            for (var i = 0; i < statusList.Length; i++)
                if (statusList[i].ing && statusList[i].buff.refInfo.id == buffId && statusList[i].cast == cast)
                    return statusList[i].number;

            return 0;
        }

        public void DeleteBuff(Cast cast, int buffId, int number)
        {
            var index = -1;
            for (var i = 0; i < statusList.Length; i++)
                if (statusList[i].ing && statusList[i].buff.refInfo.id == buffId && statusList[i].cast == cast)
                {
                    index = i;
                    break;
                }

            if (index == -1) return;

            OnUpdateStatus(index, statusList[index].number - number);
        }

        private void CheckStatus()
        {
            var time = DateTools.GetNowTime();
            var num = 0;
            for (var i = 0; i < statusList.Length; i++)
            {
                if (!statusList[i].ing) continue;
                // 持续时间大于当前时间删除状态
                if (statusList[i].time == -1 || statusList[i].time >= time)
                {
                    num++;
                    // 间隔时间大于当前时间不执行
                    if (statusList[i].lastTime == -1 || statusList[i].lastTime > time) continue;
                    _self.OnBuff(statusList[i].cast, statusList[i].buff, statusList[i].time);
                    statusList[i].Next(time);
                }
                else
                {
                    OnUpdateStatus(i, 0);
                    if (statusList[i].buff.effect != null) RemoveEffect(statusList[i].buff.effect);
                }
            }

            // 如果不存在状态 关闭检查
            if (num == 0) CloseCheck();
        }

        public void OnUpdateStatus(int index, int number)
        {
            var attrData = _self.GetData().GetAttr();
            var status = statusList[index];
            var b = 0;
            if (number <= 0)
            {
                // 移除buff增量attr
                b = status.buff.overlying ? status.number * -1 : -1;
                status.ing = false;
                status.number = 0;
            }
            else
            {
                // 重新调整buff增量attr
                b = status.buff.overlying ? number - status.number : status.number == 0 ? 1 : 0;
                status.ing = true;
                status.number = number;
            }

            if (b != 0) status.buff.attrEffect?.Effect(attrData, b);

            statusList[index] = status;

            if (_notice != null) _notice.UpdateStatus(index, status);
        }

        private SwitchEffect MakeEffect(string name)
        {
            var e = ObjectService.single.MakeEffect(name, gameObject);
            if (e != null) return e.GetComponent<SwitchEffect>();
            return null;
        }

        private void AddEffect(string name)
        {
            if (!effectMap.ContainsKey(name))
            {
                var effect = MakeEffect(name);
                if (effect == null) return;
                effectMap.Add(name, effect);
            }

            effectMap[name].Open();
        }

        private void RemoveEffect(string name)
        {
            if (effectMap.ContainsKey(name)) effectMap[name].Close();
        }

        public interface Notice
        {
            void UpdateStatus(int index, Status status);
        }
    }
}